/***************************************************************************
    copyright            : Kashyap R Puranik
    email                : kashthealien@gmail.com
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "nuclearCalculator.h"
#include <math.h>

nuclearCalculator::nuclearCalculator( QWidget * parent )
	: QFrame ( parent )
{	
	ui . setupUi( this );
	
	/**************************************************************************/
	//						 Nuclear Calculator set up
	/**************************************************************************/
	KalziumDataObject *kdo = KalziumDataObject::instance();
	
	// add all element names to the comboBox	
	foreach (Element * e, kdo->ElementList) {
    	ui . element -> addItem ( e->dataAsString ( ChemicalDataObject::name ) );
    }
    
    // Add all isotope names of Uranium ( by default )to the isotope comboBox
    QList<Isotope*> list = KalziumDataObject::instance() -> isotopes( 91 );
    QString isotope;
    foreach( Isotope * i , list ) {
    	isotope . setNum ( i -> mass () );
    	ui . isotope  -> addItem ( isotope );
    }
    // initialise the initially selected values
    ui . element  -> setCurrentIndex ( 91 );
    ui . isotope  -> setCurrentIndex ( 26 );
	ui . halfLife  -> setValue ( list. at ( 26 ) -> halflife() );
	
	// Setup of the UI done
	// Initialise values
	m_initAmount  = 0.0;
	m_finalAmount = 0.0;
	m_time = 0.0;
	m_element = * KalziumDataObject::instance() -> element ( 92 );
	m_isotope = * list . at ( 26 );
	m_halfLife = list . at ( 26 ) -> halflife ();
    // Initialisation of values done
    // Connect signals with slots
    connect ( ui . element  ,  SIGNAL ( activated ( int ) ), 
             this, SLOT ( elementChanged  ( int ) ) );
	connect ( ui . isotope  ,  SIGNAL ( activated ( int ) ),
	         this, SLOT ( isotopeChanged  ( int ) ) );
	connect ( ui . halfLife  , SIGNAL ( valueChanged ( double ) ),
	         this, SLOT ( halfLifeChanged  ( double ) ) );
	connect ( ui . initAmt  ,  SIGNAL ( valueChanged ( double ) ),
			 this, SLOT ( initAmtChanged  () ) );
	connect ( ui . finalAmt  ,  SIGNAL ( valueChanged ( double ) ),
			 this, SLOT ( finalAmtChanged  () ) );
	connect ( ui . time  ,  SIGNAL ( valueChanged ( double ) ),
			 this, SLOT ( timeChanged  () ) );
	connect ( ui . slider  , SIGNAL ( valueChanged ( int )),
			 this, SLOT ( sliderMoved  ( int ) ) );
			 	 			 
	/**************************************************************************/        
	// Nuclear Calculator setup complete	         
	/**************************************************************************/
}

nuclearCalculator:: ~nuclearCalculator()
{

}

// This function is executed when the element is changed
void nuclearCalculator::elementChanged  ( int index )
{
	// set the newly chosen element
	m_element = * KalziumDataObject::instance () -> element ( index + 1 );
	
	// Add all isotope names of Uranium ( by default ) to the isotope comboBox
    QList<Isotope*> list = KalziumDataObject::instance() -> isotopes( index + 1 );
    QString isotope;						// A temporary string
    ui . isotope  -> clear (); 				// Clear the contents of the combo box
    
    // update the combobox with isotopes of the new element
    foreach( Isotope * i , list ) {
    	isotope . setNum ( i -> mass () );
    	ui . isotope  -> addItem ( isotope );
    }
    
    // Set the halfLife to that of the first isotope of the element.
    ui . halfLife  -> setValue ( list. at ( 0 ) -> halflife());
	// Recalculate and update    
    this -> calculate  ();
}

// This function is executed when the isotope is changed
void  nuclearCalculator::isotopeChanged  ( int index )
{
	// update the nuclear Calculator
	int elementNumber = ui.element  -> currentIndex() + 1;
	QList<Isotope*> list = KalziumDataObject::instance() -> isotopes( elementNumber );
	m_isotope = * list . at ( index );

	// get the halfLife of the new isotope
	double halfLife = list . at ( index ) -> halflife ();
	
	// Update the UI with the halfLife value
	ui . halfLife -> setValue ( halfLife );
	// Recalculate and update
    this -> calculate  ();	
}

// This function is executed when the halfLife is changed
void  nuclearCalculator::halfLifeChanged  ( double value )
{
	// update the nuclear Calculator
	m_halfLife = value;
	// Recalculate and update
    this -> calculate  ();	
}

void  nuclearCalculator::initAmtChanged  ( )
{
	double initAmt = ui . initAmt  -> value ();
	m_initAmount = initAmt;
	
	/*if ( ui . r1  -> isChecked () )
		ui . r3  -> setChecked ( TRUE );*/
	this -> calculate  ();
}

void  nuclearCalculator::finalAmtChanged  ()
{
	double finalAmt = ui . finalAmt  -> value ();
	m_finalAmount = finalAmt;
	
	/*if ( ui . r2  -> isChecked () )
		ui . r3  -> setChecked ( TRUE );*/
	this -> calculate  ();
}

void  nuclearCalculator::sliderMoved  ( int numHlives )
{
	double halfLife = ui . halfLife  -> value ( );
	double num = numHlives / 10.0;
	double time = num * halfLife;
	QString num_str;
	num_str . setNum ( num );

	ui . time  -> setValue ( time );
	ui . numHalfLives -> setText ( num_str );
	m_time = time;

	calculate ();
}

void  nuclearCalculator::timeChanged  ( )
{
	double time = ui . time  -> value ();
	m_time = time;
	
	/*if ( ui . r3  -> isChecked () )
		ui . r2  -> setChecked ( TRUE );*/
	this -> calculate  ();

}

void  nuclearCalculator::calculate  ( )
{
	double result;
	
	// Validate the values involved in calculation
	if ( ui . halfLife  -> value () == 0.0 )
		return;
	
	if ( ui . r1  -> isChecked () )	// Calculate initial amount
	{
		if ( ui . finalAmt  -> value () == 0.0 )
			return;
		result = calculateInitAmount ();
		ui . initAmt  -> setValue ( result );
			
	}
	// Calulate final Amount after time
	else if ( ui . r2  -> isChecked () )
	{
		if ( ui. initAmt  -> value() == 0.0 )
			return;
		result = calculateFinalAmount ();
		ui . finalAmt  -> setValue ( result );		
	
	}
	else	// Calculate Time
	{
		// final amount greater than initial
		if ( ui . finalAmt  -> value () > ui . initAmt  -> value() )
			return;
		// one of the amounts is 0.0
		if ( ui . finalAmt  -> value () == 0.0 || ui . initAmt  -> value () == 0.0 )
			return;

		result = calculateTime ();
		ui . time  -> setValue ( result );			
	}
}

double nuclearCalculator::calculateInitAmount ( void )
{
	double amount = m_finalAmount;

	if ( m_time == 0.0 )
		return m_finalAmount;
	amount *= pow ( 2.0 , m_time / m_halfLife );

	return amount;
}

double nuclearCalculator::calculateFinalAmount ( void )
{
	if ( m_time == 0.0 )
		return m_initAmount;
	double amount = m_initAmount;
	
	amount /= pow ( 2.0, m_time / m_halfLife );
	
	return amount;
}

double nuclearCalculator::calculateTime ( void )
{
	double ratio = m_initAmount / m_finalAmount;		// calculate the ratio of final to initial
	double numHalfLives = log ( ratio )/ log ( 2.0 );	// The number of halfLives ( log 2 ( x ) = log x / log 2 )
	double time = numHalfLives * m_halfLife;			// The total time taken

	if ( m_initAmount == m_finalAmount )
		return 0.0;
	
	return time;
}

#include "nuclearCalculator.moc"


